commonlibsse_ng_proc_macro_common/
fn_args_parser.rs

1use proc_macro2::TokenStream;
2use syn::{FnArg, punctuated::Punctuated, token::Comma};
3
4pub struct FnArgs {
5   pub call_args: proc_macro2::TokenStream,
6   pub type_args: proc_macro2::TokenStream,
7   pub self_type: Option<proc_macro2::TokenStream>,
8   pub cast_self: Option<proc_macro2::TokenStream>,
9}
10
11/// Helper function to create function arguments based on argument lists and variable arguments
12pub fn create_fn_args(
13    fn_inputs: &Punctuated<FnArg, Comma>,
14    variadic: &Option<syn::Variadic>,
15) -> FnArgs {
16    let mut call_args = vec![];
17    let mut type_args = vec![];
18    let mut self_type = None;
19    let mut cast_self = None;
20
21    for arg in fn_inputs {
22        match arg {
23            syn::FnArg::Typed(pat_type) => {
24                let pat = &pat_type.pat;
25                if let syn::Pat::Ident(ident) = &**pat {
26                    if ident.ident == "self" {
27                        let syn::PatIdent { by_ref, mutability, .. } = ident;
28                        let (self_type_, cast_self_) =
29                            create_self_and_cast(by_ref.is_some(), mutability.is_some());
30                        self_type = Some(self_type_);
31                        cast_self = Some(cast_self_);
32                        continue;
33                    }
34                }
35
36                let ident = &pat_type.pat;
37                let ty = &pat_type.ty;
38                call_args.push(quote::quote! { #ident  });
39                type_args.push(quote::quote! { #ty });
40            }
41            syn::FnArg::Receiver(receiver) => {
42                let reference = receiver.reference.as_ref().map(|(and, _lifetime)| and);
43                let mutability = &receiver.mutability;
44
45                let (self_type_, cast_self_) =
46                    create_self_and_cast(reference.is_some(), mutability.is_some());
47                self_type = Some(self_type_);
48                cast_self = Some(cast_self_);
49            }
50        }
51    }
52
53    if variadic.is_some() {
54        call_args.push(quote::quote! { ... });
55    }
56
57    FnArgs {
58        call_args: quote::quote! { #(#call_args),* },
59        type_args: quote::quote! { #(#type_args),* },
60        self_type,
61        cast_self,
62    }
63}
64
65fn create_self_and_cast(by_ref: bool, mutability: bool) -> (TokenStream, TokenStream) {
66    match (by_ref, mutability) {
67        (true, true) => (quote::quote! { *mut (), }, quote::quote! { (self as *mut Self).cast(), }),
68        (true, false) => {
69            (quote::quote! { *const (), }, quote::quote! { (self as *const Self).cast(), })
70        }
71        (false, _) => (
72            quote::quote! { *mut (), },
73            quote::quote! { Box::into_raw(Box::new(self) as *mut ()), }, // NOTE: mem leak
74        ),
75    }
76}